<!-- 组件代码 -->
<template>
  <el-select
    ref="elSelectRef"
    v-model="value"
    :placeholder="placeholder ? placeholder : '请选择'"
    :multiple="multiple ? multiple : false"
    :filterable="filterable ? filterable : false"
    :clearable="clearable ? clearable : false"
    :disabled="disabled ? disabled : false"
    :collapseTags="collapseTags ? collapseTags : false"
    :allowCreate="allowCreate ? allowCreate : false"
    :valueKey="valueKey ? valueKey : 'value'"
    :filterMethod="filterMethodT"
    :remote="remote ? remote : false"
    :remoteMethod="remoteMethodT"
    :remoteShowSuffix="remoteShowSuffix ? remoteShowSuffix : false"
    :loading="loading ? loading : false"
    :size="size ? size : 'default'"
    :popperClass="popperClass ? popperClass : undefined"
    :defaultFirstOption="defaultFirstOption ? defaultFirstOption : false"
    :teleported="teleported ? teleported : true"
    @change="onChange"
    @blur="onBlur"
    @focus="onFocus"
    @visible-change="visibleChange"
  >
    <el-option v-for="(item, key) in extraOptions" :key="key" :label="item.label" :value="item.value" />
    <!-- <el-option :label="`test`" :value="-1"></el-option> -->
    <slot />
    <div class="no-more">没有更多了</div>
    <div class="no-more" v-show="noMoreVisible">没有更多了</div>
  </el-select>
</template>
<script setup lang="ts">

const props = defineProps<{
  pageOption: { current: number, size: number, total: number },
  modelValue?: any,
  multiple?: boolean,
  disabled?: boolean,
  valueKey?: string,
  size?: "" | "default" | "small" | "large" | undefined,
  clearable?: boolean,
  collapseTags?: boolean,
  placeholder?: string,
  filterMethod?: Function,
  remote?: boolean,
  remoteMethod?: Function,
  remoteShowSuffix?: boolean,
  loading?: boolean,
  loadingText?: string,
  noMatchText?: string,
  noDataText?: string,
  popperClass?: string,
  defaultFirstOption?: boolean,
  teleported?: boolean,
  allowCreate?: boolean,
  filterable?: boolean,
  // 可能存在的选项（在修改了选中值之后会修改为选中值）
  mayNotExistOptions?: string | string[] | DYOptionType[] | undefined
}>()
const emits = defineEmits([
  'update:modelValue', 'change', 'current-page'
])

const elSelectRef = ref<Selection>()
const value = ref(undefined)
if (props.modelValue) {
  value.value = props.modelValue
}
watch(() => props.modelValue, () => {
  value.value = props.modelValue
})

// 判断是否使用过mayNotExistOptions该值
let useMayExistOptions = false
onMounted(() => {
  if (props.pageOption !== undefined && props.pageOption.current !== undefined && props.pageOption.size !== undefined && props.pageOption.total !== undefined) {
    openScrollEvent()
  } else {
    console.warn('未传入分页属性！未开启分页功能！ -- DianaYako')
  }
  // 如果传入属性值中存在可能存在的选项 那么进行配置一下
  if (props.mayNotExistOptions && !useMayExistOptions) {
    useMayExistOptions = true
    setMayNotExistOptions(props.mayNotExistOptions)
  }
})
// 监听mayNotExistOptions改变 第一次改变去配置可能存在的值
watch(() => props.mayNotExistOptions, () => {
  if (props.mayNotExistOptions && !useMayExistOptions) {
    useMayExistOptions = true
    setMayNotExistOptions(props.mayNotExistOptions)
  }
})

/** 组件数据 */
// 可能不存在于选项列表的选项
const notExistOptions = ref<DYOptionType[]>([])
/** 计算属性 */
/**
 * 显示在选项列表中的选项
 */
const extraOptions = computed(() => {
  let arr = notExistOptions.value.filter(item => {
    return noExistLabelVisible(item)
  })
  return arr
})
/**
 * 是否显示没有更多
 */
const noMoreVisible = computed(() => {
  if (props.pageOption !== undefined && props.pageOption.current !== undefined && props.pageOption.size !== undefined && props.pageOption.total !== undefined) {
    if (props.pageOption.total === 0) {
      return true
    } else if (props.pageOption.current * props.pageOption.size <= props.pageOption.total) {
      return false
    } else {
      if (props.pageOption.current !== 1) return true
      else return false
    }
  } else {
    return false
  }
})
/** 选择框原生事件 */
/**
 * 下拉框出现/隐藏时触发
 */
const visibleChange = (visible: boolean) => {
  // if (!visible) {
  //   remoteMethodT('')
  // }
}
/**
 * 当 input 失去焦点时触发
 */
const onBlur = () => {
  // console.log('失去焦点')
}
/**
 *	当 input 获得焦点时触发
 */
const onFocus = () => {
  // console.log('获得焦点')
}
/**
 * 触发filterMethod
 */
const filterValue = ref('')
const filterMethodT = (e: string) => {
  filterValue.value = e
  if (props.filterMethod) {
    setTimeout(() => {
      props.filterMethod && props.filterMethod(e)
    }, 100);
  }
}
/**
 * 选择框触发筛选
 */
const remoteValue = ref('')
const remoteMethodT = (e: string) => {
  remoteValue.value = e
  if (props.remoteMethod) {
    setTimeout(() => {
      props.remoteMethod && props.remoteMethod(e)
    }, 100);
  }
}
/**
 * 选择框发生改变
 */
const onChange = (e: any) => {
  emits('update:modelValue', e)
  emits('change', e)
  // 发生改变后处理一下不存在的值
  if (props.multiple) {
    // 如果是多选 区分一下 那些需要删除掉
    if (!props.modelValue || props.modelValue.length === 0) {
      notExistOptions.value = []
    } else {
      if (notExistOptions.value.length > 0) {
        notExistOptions.value.forEach((item, key) => {
          let i2 = props.modelValue.findIndex((item2: number) => item2 === item.value)
          if (i2 === -1) {
            notExistOptions.value.splice(key, 1)
          }
        })
      }
    }
  } else {
    // 如果是单选 那么清空
    notExistOptions.value = []
  }
}
/** 方法 */
/**
 * 判断是否显示不存在的值
 */
const noExistLabelVisible = (option: DYOptionType) => {
  // 检查当前选项是否是搜索结果
  if (filterValue.value || remoteValue.value) {
    return false
  }
  // 查找当前选项是否不在当前选项中
  if (useSlots() && useSlots().default && useSlots().default!() && useSlots().default!()[0] && useSlots().default!()[0].children)  {
    if (Array.isArray(useSlots().default!()[0].children)) {
      let arr: any = useSlots().default!()[0].children
      let filterArr = arr?.filter((item: { props: { value: any } }) => (item.props && item.props.value))
      let existFlag = filterArr.findIndex((item: { props: { value: string | number } }) => {
        return item.props.value === option.value
      })
      if (existFlag === -1) {
        return true
      } else {
        return false
      }
    } else {
      return false
    }
  } else {
    return false
  }
}
/**
 * 开启滚动监听
 */
const openScrollEvent = () => {
  // 监听滚动
  if (elSelectRef.value && (elSelectRef.value as any).popperPaneRef) {
    let elPopperDom: HTMLElement = (elSelectRef.value as any).popperPaneRef
    let elSelectDropdown = elPopperDom.querySelector('div.el-select-dropdown')
    if (elSelectDropdown) {
      let elScorllbarDom = elPopperDom.querySelector('div.el-scrollbar')
      if (elScorllbarDom) {
        let elSelectDropdownWrapDom: HTMLElement | { addEventListener: any, scrollHeight: number, scrollTop: number, clientHeight: number } | null = elScorllbarDom.querySelector('div.el-select-dropdown__wrap')
        if (elSelectDropdownWrapDom) {
          elSelectDropdownWrapDom.addEventListener('scroll', () => {
            if (elSelectDropdownWrapDom) {
              const bottom = elSelectDropdownWrapDom.scrollHeight - elSelectDropdownWrapDom.scrollTop === elSelectDropdownWrapDom.clientHeight;
              if (bottom) {
                currentPage()
              }
            }
          })
        } else {
          console.error('滚动加载组件无法获取到对应DOM！请检查组件代码！ -- DianaYao');
        }
      } else {
        console.error('滚动加载组件无法获取到对应DOM！请检查组件代码！ -- DianaYao');
      }
    } else {
      console.error('滚动加载组件无法获取到对应DOM！请检查组件代码！ -- DianaYao');
    }
  } else {
    console.error('滚动加载组件无法获取到对应DOM！请检查组件代码！ -- DianaYao');
  }
}
/**
 * 触发分页
 */
const currentPage = () => {
  if (props.pageOption && props.pageOption.current && props.pageOption.size && props.pageOption.total) {
    if (props.pageOption.current * props.pageOption.size <= props.pageOption.total) {
      emits('current-page', props.pageOption.current + 1)
    }
  }
}
/**
 * 设置可能不存在于选项的已选选项
 * @param options 传入可能不存在的选项的信息
 *                如果是字符串：这里认为是选项的label【显示值】
 *                如果是字符串数组：这里认为是多个可能不存在的选项的的label【显示值】
 *                如果是对象数组：传入数组的每一项必须是对象并且必须有label、value字段，其他不做处理。
 */
type DYOptionType = {
  label: string
  value: string | number
}
const setMayNotExistOptions = (options: string | string[] | DYOptionType[]) => {
  if (typeof options === 'string') {
    props.modelValue && notExistOptions.value.push({ label: options, value: props.modelValue })
  } else if (Array.isArray(options) && options.length > 0) {
    let optionsT: DYOptionType[] = []
    options.forEach((item: DYOptionType | string, key: number) => {
      if (typeof item === 'string') {
        if (props.modelValue) {
          optionsT.push({
            label: item,
            value: (props.modelValue[key]) ? props.modelValue[key] : (0 - (optionsT.length + 1))
          })
        }
      } else if (typeof item === 'object') {
        if (item.label !== undefined && item.value !== undefined && item.label !== null && item.value !== null) {
          optionsT.push(item)
        }
      }
    })
    notExistOptions.value = optionsT
  }
}

defineExpose({ elSelectRef, setMayNotExistOptions })
</script>
<style scoped lang="scss">
  .no-more {
    text-align: center;
    padding: 5px 0 0px;
    color: #979797;
    font-size: 12px;
  }
</style>



